#include "sht3x_drv.h"

#include "sht3x_utils.h"

#include "hdf_log.h"

// i2c
#include "i2c_if.h"

// sensor
#include "sensor_common.h"
#include "sensor_device_common.h"
#include "sensor_device_manager.h"

// SHT3X 指令表
#define     CMD_READ_SERIALNBR  (0x3780)  // read serial number
#define     CMD_READ_STATUS 	(0xF32D)  // read status register
#define     CMD_CLEAR_STATUS 	(0x3041)  // clear status register
#define     CMD_HEATER_ENABLE 	(0x306D)  // enabled heater
#define     CMD_HEATER_DISABLE 	(0x3066)  // disable heater
#define     CMD_SOFT_RESET 		(0x30A2)  // soft reset

#define     CMD_MEAS_CLOCKSTR_H (0x2C06)  // measurement: clock stretching, high repeatability
#define     CMD_MEAS_CLOCKSTR_M (0x2C0D)  // measurement: clock stretching, medium repeatability
#define     CMD_MEAS_CLOCKSTR_L (0x2C10)  // measurement: clock stretching, low repeatability

#define     CMD_MEAS_POLLING_H 	(0x2400)  // measurement: polling, high repeatability
#define     CMD_MEAS_POLLING_M 	(0x240B)  // measurement: polling, medium repeatability
#define     CMD_MEAS_POLLING_L 	(0x2416)  // measurement: polling, low repeatability

#define     CMD_MEAS_PERI_05_H 	(0x2032)  // measurement: periodic 0.5 mps, high repeatability
#define     CMD_MEAS_PERI_05_M 	(0x2024)  // measurement: periodic 0.5 mps, medium repeatability
#define     CMD_MEAS_PERI_05_L 	(0x202F)  // measurement: periodic 0.5 mps, low repeatability

#define     CMD_MEAS_PERI_1_H 	(0x2130)  // measurement: periodic 1 mps, high repeatability
#define     CMD_MEAS_PERI_1_M 	(0x2126)  // measurement: periodic 1 mps, medium repeatability
#define     CMD_MEAS_PERI_1_L 	(0x212D)  // measurement: periodic 1 mps, low repeatability

#define     CMD_MEAS_PERI_2_H 	(0x2236)  // measurement: periodic 2 mps, high repeatability
#define     CMD_MEAS_PERI_2_M 	(0x2220)  // measurement: periodic 2 mps, medium repeatability
#define     CMD_MEAS_PERI_2_L 	(0x222B)  // measurement: periodic 2 mps, low repeatability

#define     CMD_MEAS_PERI_4_H 	(0x2334)  // measurement: periodic 4 mps, high repeatability
#define     CMD_MEAS_PERI_4_M 	(0x2322)  // measurement: periodic 4 mps, medium repeatability
#define     CMD_MEAS_PERI_4_L 	(0x2329)  // measurement: periodic 4 mps, low repeatability

#define     CMD_MEAS_PERI_10_H 	(0x2737)  // measurement: periodic 10 mps, high repeatability
#define     CMD_MEAS_PERI_10_M 	(0x2721)  // measurement: periodic 10 mps, medium repeatability
#define     CMD_MEAS_PERI_10_L 	(0x272A)  // measurement: periodic 10 mps, low repeatability

#define     CMD_MEAS_PERI_STOP  (0x3093)  // stop periodic measurement

#define     CMD_FETCH_DATA 		(0xE000)  // readout measurements for periodic mode

#define     CMD_R_AL_LIM_LS 	(0xE102)  // read alert limits, low set
#define     CMD_R_AL_LIM_LC 	(0xE109)  // read alert limits, low clear
#define     CMD_R_AL_LIM_HS 	(0xE11F)  // read alert limits, high set
#define     CMD_R_AL_LIM_HC 	(0xE114)  // read alert limits, high clear
#define     CMD_W_AL_LIM_HS 	(0x611D)  // write alert limits, high set
#define     CMD_W_AL_LIM_HC 	(0x6116)  // write alert limits, high clearSample Code for SHT3x
#define     CMD_W_AL_LIM_LC 	(0x610B)  // write alert limits, low clear
#define     CMD_W_AL_LIM_LS 	(0x6100)  // write alert limits, low set

#define     CMD_NO_SLEEP 		(0x303E) 

#define     SHT3X_THREAD_NAME_LEN   (32)
#define     SHT3X_THREAD_NAME_FMT   "sht3x/%#x@i2c%d/sampling"

// 日志标记
#define HDF_LOG_TAG     sht3xDrv

// 参数检查宏定义
#define SHT3X_CHECK_NULL_PTR_RET(ptr, ret) \
do { \
    if (NULL == (ptr)) {  \
        HDF_LOGE("[%s] %d : ptr is null.", __FUNCTION__, __LINE__); \
        return (ret); \
    } \
} while(0) 

#define SHT3X_CHECK_NULL_PTR(ptr) \
do { \
    if (NULL == (ptr)) {  \
        HDF_LOGE("[%s] %d : ptr is null.", __FUNCTION__, __LINE__); \
        return; \
    } \
} while(0) 

// 私有结构体
typedef struct {

    bool enabled;            // 是否使能
    struct OsalMutex mutex;     // 锁

    char samplingThreadName[SHT3X_THREAD_NAME_LEN];// 采样线程名
    struct OsalThread samplingThread;// 采样线程
    uint8_t samplingThreadStatus;// 采样线程状态

    // 总线相关
    uint16_t slaveAddr;         // 从器件地址 只能通过pin引脚的电平设置
    DevHandle host;                 // 总线

    uint64_t timeStampMs;       // 上一次采样的时间
    int64_t samplingInterval;   // 采样时间间隔 

    uint8_t measureMode;        // 当前设备的工作模式 period/poll/clk_stretch
    uint8_t mode;               // 暂存mode

    uint16_t readDataCmd;       // 暂存数据读取的指令

    sht3x_data data;            // 温湿度数据 缓冲区

    // struct SensorDeviceInfo temperatureSensorInfo;  // 温度节点
    // struct SensorDeviceInfo humiditySensorInfo;     // 湿度节点
} sht3x_drv_t;

/*
获取周期
Get Interval(ms) By Measure Frequency(period measure mode)
0.5Hz   -> 2000(ms)
1Hz     -> 1000(ms)
2Hz     -> 500(ms)
4Hz     -> 250(ms)
10Hz    -> 100(ms)
other   -> -1
*/
static inline int64_t _sht3xDrvGetIntervalByFreq(uint8_t freq)
{
    switch(freq)
    {
        case SHT3X_FREQUENCY_HZ5:
            return (2000);
        case SHT3X_FREQUENCY_1HZ:
            return (1000);
        case SHT3X_FREQUENCY_2HZ:
            return (500);
        case SHT3X_FREQUENCY_4HZ:
            return (250);
        case SHT3X_FREQUENCY_10HZ:
            return (100);
        default:
            return (-1);
    }

    return (-1);
}

/*
获取模式对应的周期
Get Measure Frequency By Mode(period measure mode)
see @MeasureMode in sht3x.h
*/
static inline uint8_t _sht3xDrvGetFreqByMode(uint8_t mode)
{
#define SHT3X_FREQ_UNMASK(mode)             ((mode>>0)&0x7)
    uint8_t freq = SHT3X_FREQ_UNMASK(mode);

    switch(freq)
    {
        case SHT3X_FREQUENCY_HZ5:
        case SHT3X_FREQUENCY_1HZ:
        case SHT3X_FREQUENCY_2HZ:
        case SHT3X_FREQUENCY_4HZ:
        case SHT3X_FREQUENCY_10HZ:
            return freq;
        break;
        default:
            return (-1);
        break;
    }

    return (-1);
}

//////////////////////////////////////////////////
// 参数设置
//////////////////////////////////////////////////

/*
设置设备的从器件地址
set device slave address
*/
static inline int32_t _sht3xDrvSetSlaveAddr(sht3x_drv_t *drv, uint16_t addr)
{
    // 确保从器件地址配置是正确的
    // ensure slave address is correct
    if (addr != 0x44 && addr != 0x45) return HDF_FAILURE;
    drv->slaveAddr = addr;
    return HDF_SUCCESS;
}

/*
获取设备的从器件地址
get device slave address
*/
static inline uint16_t _sht3xDrvGetSlaveAddr(sht3x_drv_t *drv)
{
    return drv->slaveAddr;
}

/*
设置采样周期
set device sampling interval
*/
static inline int32_t _sht3xDrvSetSamplingInterval(sht3x_drv_t *drv, int64_t interval)
{
    // 对周期做一个限制 100ms(10Hz) 
    // interval at least 100ms(10Hz)
    if (interval < 100) {
        interval = 100;
    }

    drv->samplingInterval = interval;
    return HDF_SUCCESS;
}

/*
获取采样周期
set device sampling interval
*/
static inline int64_t _sht3xDrvGetSamplingInterval(sht3x_drv_t *drv)
{
    return drv->samplingInterval;
}

/*
设置设备私有属性
set device private data
use to save i2c handler
*/
static inline int32_t _sht3xDrvSetHost(sht3x_drv_t *drv, DevHandle host)
{
    drv->host = host;
    return HDF_SUCCESS;
}

/*
获取设备私有属性
get device private data
use to save i2c handler
*/
static inline DevHandle _sht3xDrvGetHost(sht3x_drv_t *drv)
{
    return drv->host;
}

/*
设置设备模式
set device work mode
see @Repeatab @MeasureMode @Frequency in sht3x.h
*/
static inline int32_t _sht3xDrvSetMode(sht3x_drv_t *drv, uint8_t mode)
{
    // 检查 mode 是否正确
    // check work mode is correct
    switch (mode)
    {
        // poll
        case SHT3X_MODE_POLL_H:         
        case SHT3X_MODE_POLL_M:         
        case SHT3X_MODE_POLL_L:         
        // clk stretch
        case SHT3X_MODE_CLK_STRETCH_H:  
        case SHT3X_MODE_CLK_STRETCH_M:  
        case SHT3X_MODE_CLK_STRETCH_L:
        // 0.5
        case SHT3X_MODE_PERIOD_HZ5_H:   
        case SHT3X_MODE_PERIOD_HZ5_M:   
        case SHT3X_MODE_PERIOD_HZ5_L:   
        // 1
        case SHT3X_MODE_PERIOD_1HZ_H:   
        case SHT3X_MODE_PERIOD_1HZ_M:   
        case SHT3X_MODE_PERIOD_1HZ_L:   
        // 2
        case SHT3X_MODE_PERIOD_2HZ_H:   
        case SHT3X_MODE_PERIOD_2HZ_M:   
        case SHT3X_MODE_PERIOD_2HZ_L:   
        // 4
        case SHT3X_MODE_PERIOD_4HZ_H:   
        case SHT3X_MODE_PERIOD_4HZ_M:   
        case SHT3X_MODE_PERIOD_4HZ_L:   
        // 10
        case SHT3X_MODE_PERIOD_10HZ_H:  
        case SHT3X_MODE_PERIOD_10HZ_M:  
        case SHT3X_MODE_PERIOD_10HZ_L:  
            drv->mode = mode;
            return HDF_SUCCESS;
        break;
        default: 
            // work mode error
            drv->mode = SHT3X_MODE_NONE;
            return HDF_FAILURE;
        break;
    }

    return HDF_FAILURE;
}

/*
获取设备当前的模式
get device work mode
*/
static inline uint8_t _sht3xDrvGetMode(sht3x_drv_t *drv)
{
    return drv->mode;
}

/*
设置设备的测量模式 period poll clk_stretch
set device measure mode [ period | poll | clk_stretch ]

see @MeasureMode in sht3x.h

该函数在 SetMode 之后调用,不对输入参数 mode 进行判断
this function called after _sht3xDrvSetMode(), no need to check input parameter "mode"
*/
static inline int32_t _sht3xDrvSetMeasureMode(sht3x_drv_t *drv, uint8_t mode)
{
#define SHT3X_MEASURE_MODE_UNMASK(mode)     ((mode>>4)&0x3)
    drv->measureMode = SHT3X_MEASURE_MODE_UNMASK(mode);

    switch (drv->measureMode)
    {
        case SHT3X_PERIOD:
        case SHT3X_POLL:
        case SHT3X_CLK_STRETCH:
            return HDF_SUCCESS;
            break;
        default:    // 模式设置有问题 measure mode error
            drv->measureMode = (0x00);
            break;
    }

    return HDF_FAILURE;
}

/*
获取当前设备的测量模式
get device measure mode [ period | poll | clk_stretch ]

see @MeasureMode in sht3x.h
*/
static inline uint8_t _sht3xDrvGetMeasureMode(sht3x_drv_t *drv)
{
    return drv->measureMode;
}

/*
设置读取数据指令
set device read data cmd

use this like a cache
*/
static inline int32_t _sht3xDrvSetReadDataCmd(sht3x_drv_t *drv, uint16_t cmd)
{
    drv->readDataCmd = cmd;
    return HDF_SUCCESS;
}

/*
获取读取数据指令
get devide read data cmd
*/
static inline uint16_t _sht3xDrvGetReadDataCmd(sht3x_drv_t *drv)
{
    return drv->readDataCmd;
}

/*
上锁
lock
*/
static inline int32_t _sht3xDrvMutexLock(sht3x_drv_t *drv)
{
    return OsalMutexTimedLock(&(drv->mutex), 100);
}

/*
解锁
unlock
*/
static inline int32_t _sht3xDrvMutexUnLock(sht3x_drv_t *drv)
{
    return OsalMutexUnlock(&(drv->mutex));
}

// 设置时间戳
static inline int32_t _sht3xDrvSetTimeStamp(sht3x_drv_t *drv, uint64_t timeStampMs)
{
    drv->timeStampMs = timeStampMs;
    return HDF_SUCCESS;
}

// 获取时间戳
static inline uint64_t _sht3xDrvGetTimeStamp(sht3x_drv_t *drv)
{
    return drv->timeStampMs;
}

/*
设置线程状态
*/
static inline int32_t _sht3xDrvSetThreadStatus(sht3x_drv_t *drv, uint8_t status)
{
    drv->samplingThreadStatus = status;
    return HDF_SUCCESS;
}

/*
获取线程状态
*/
static inline uint8_t _sht3xDrvGetThreadStatus(sht3x_drv_t *drv)
{
    return drv->samplingThreadStatus;
}

/*
设备使能
*/
static inline int32_t _sht3xDrvEnable(sht3x_drv_t *drv)
{
    drv->enabled = true;
    return HDF_SUCCESS;
}

/*
设备失能
*/
static inline int32_t _sht3xDrvDisable(sht3x_drv_t *drv)
{
    drv->enabled = false;
    return HDF_SUCCESS;
}

/*
设备使能状态
*/
static inline bool _sht3xDrvIsEnabled(sht3x_drv_t *drv)
{
    return drv->enabled;
}

//////////////////////////////////////////////////
// 数据传输
//////////////////////////////////////////////////

/*
通过设置的模式 获取对应的要发送的指令
get cmd by work mode

如果是周期测量模式
指令用于启动周期测量

if current is period measure mode, cmd use to start period measure

如果是poll或者时钟拉伸模式
指令在读取数据的时候用到

if is poll or clk stretch mode, cmd use to trigger single measure
*/
static int32_t _sht3xDrvGetCmdByMode(sht3x_drv_t *drv, uint16_t *cmd)
{
    int32_t ret = HDF_SUCCESS;

    // 根据 mode 获取读取数据时要发送的指令
    switch (_sht3xDrvGetMode(drv))
    {
        // poll
        case SHT3X_MODE_POLL_H:         *cmd = CMD_MEAS_POLLING_H; break;
        case SHT3X_MODE_POLL_M:         *cmd = CMD_MEAS_POLLING_M; break;
        case SHT3X_MODE_POLL_L:         *cmd = CMD_MEAS_POLLING_L; break;

        // clk stretch
        case SHT3X_MODE_CLK_STRETCH_H:  *cmd = CMD_MEAS_CLOCKSTR_H; break;
        case SHT3X_MODE_CLK_STRETCH_M:  *cmd = CMD_MEAS_CLOCKSTR_M; break;
        case SHT3X_MODE_CLK_STRETCH_L:  *cmd = CMD_MEAS_CLOCKSTR_L; break;

        // 0.5
        case SHT3X_MODE_PERIOD_HZ5_H:   *cmd = CMD_MEAS_PERI_05_H; break;
        case SHT3X_MODE_PERIOD_HZ5_M:   *cmd = CMD_MEAS_PERI_05_M; break;
        case SHT3X_MODE_PERIOD_HZ5_L:   *cmd = CMD_MEAS_PERI_05_L; break;
        
        // 1
        case SHT3X_MODE_PERIOD_1HZ_H:   *cmd = CMD_MEAS_PERI_1_H;   break;
        case SHT3X_MODE_PERIOD_1HZ_M:   *cmd = CMD_MEAS_PERI_1_M;   break;
        case SHT3X_MODE_PERIOD_1HZ_L:   *cmd = CMD_MEAS_PERI_1_L;   break;
        
        // 2
        case SHT3X_MODE_PERIOD_2HZ_H:   *cmd = CMD_MEAS_PERI_2_H;   break;
        case SHT3X_MODE_PERIOD_2HZ_M:   *cmd = CMD_MEAS_PERI_2_M;   break;
        case SHT3X_MODE_PERIOD_2HZ_L:   *cmd = CMD_MEAS_PERI_2_L;   break;
        
        // 4
        case SHT3X_MODE_PERIOD_4HZ_H:   *cmd = CMD_MEAS_PERI_4_H;   break;
        case SHT3X_MODE_PERIOD_4HZ_M:   *cmd = CMD_MEAS_PERI_4_M;   break;
        case SHT3X_MODE_PERIOD_4HZ_L:   *cmd = CMD_MEAS_PERI_4_L;   break;
        
        // 10
        case SHT3X_MODE_PERIOD_10HZ_H:  *cmd = CMD_MEAS_PERI_10_H;  break;
        case SHT3X_MODE_PERIOD_10HZ_M:  *cmd = CMD_MEAS_PERI_10_M;  break;
        case SHT3X_MODE_PERIOD_10HZ_L:  *cmd = CMD_MEAS_PERI_10_L;  break;

        default: ret = HDF_FAILURE; break;
    }

    return ret;
}

/*
往设备发送指令
send cmd to device

sht3x的指令长度是16bit
sht3x cmd length is 16bit

先发送高字节
MSB first
*/
static int32_t _sht3xDrvSendCmd(sht3x_drv_t *drv, uint16_t cmd)
{
    int32_t ret = 0;
    uint8_t send_data[2] = {cmd>>8, cmd&0xFF};
    struct I2cMsg msg = {0};
    DevHandle host = NULL;
    uint16_t addr;

    // 参数检查
    SHT3X_CHECK_NULL_PTR_RET(drv, HDF_ERR_INVALID_OBJECT);

    // 检查是否已经打开了端口
    host = _sht3xDrvGetHost(drv);
    SHT3X_CHECK_NULL_PTR_RET(host, HDF_FAILURE);

    // 获取设备从地址
    addr = _sht3xDrvGetSlaveAddr(drv);

    // 填充传输的数据
    msg.addr = addr;                        // 地址
    msg.len = 2;                            // 长度
    msg.buf = send_data;                    // 发送的数据
    msg.flags = 0;

    // 数据发送
    ret = I2cTransfer(host, &msg, 1);
    if ( ret == 1 ) ret = HDF_SUCCESS;
    return ret;
}

/*
不发送指令,直接读取数据
read $(len) byte to $(data)
*/
static int32_t _sht3xDrvReadData(sht3x_drv_t *drv, uint8_t *data, int32_t len)
{
    int32_t ret = 0;
    struct I2cMsg msg = {0};// 读取数据
    DevHandle host = NULL;
    uint16_t addr;

    // 参数检查
    SHT3X_CHECK_NULL_PTR_RET(drv, HDF_ERR_INVALID_OBJECT);
    SHT3X_CHECK_NULL_PTR_RET(data, HDF_ERR_INVALID_OBJECT);

    // 检查是否已经打开了端口
    host = _sht3xDrvGetHost(drv);
    SHT3X_CHECK_NULL_PTR_RET(host, HDF_FAILURE);

    // 如果要读取的字节数,直接返回
    if (len <= 0) { return HDF_SUCCESS; }

    // 获取设备从地址
    addr = _sht3xDrvGetSlaveAddr(drv);

    // read
    msg.addr = addr;
    msg.len = 6;
    msg.buf = data;
    msg.flags = I2C_FLAG_READ;

    // 数据发送
    ret = I2cTransfer(host, &msg, 1);
    if (ret == 1) ret = HDF_SUCCESS;

    return ret;
}

/*
发送指令 cmd 然后读取 len 个字节 放到 data 里面
send $(cmd) first and read $(len) byte to $(data)
*/
static int32_t _sht3xDrvReadDataByCmd(sht3x_drv_t *drv, uint16_t cmd, uint8_t *data, int32_t len)
{
    int32_t ret = 0;
    uint8_t send_data[2] = {cmd>>8, cmd&0xFF};
    struct I2cMsg msg[2] = {0};// 先发送,再接收
    DevHandle host = NULL;
    uint16_t addr;

    // 参数检查
    SHT3X_CHECK_NULL_PTR_RET(drv, HDF_ERR_INVALID_OBJECT);
    SHT3X_CHECK_NULL_PTR_RET(data, HDF_ERR_INVALID_OBJECT);
    
    // 检查是否已经打开了端口
    host = _sht3xDrvGetHost(drv);
    SHT3X_CHECK_NULL_PTR_RET(host, HDF_FAILURE);

    // 如果要读取的字节数,直接返回
    if (len <= 0) { return HDF_SUCCESS; }

    // 获取设备从地址
    // get devcice current slave address
    addr = _sht3xDrvGetSlaveAddr(drv);

    // send
    msg[0].addr = addr;
    msg[0].len = 2;
    msg[0].buf = send_data;
    msg[0].flags = 0;

    // read
    msg[1].addr = addr;
    msg[1].len = 6;
    msg[1].buf = data;
    msg[1].flags = I2C_FLAG_READ;

    // 数据发送
    ret = I2cTransfer(host, msg, 2);
    if (ret == 2) ret = HDF_SUCCESS;

    return ret;
}

//////////////////////////////////////////////////
// 数据读取操作
//////////////////////////////////////////////////

/*
周期测量模式下读取测量到的温湿度数值
read data at period measure mode
*/
static int32_t _sht3xDrvReadDataPeriod(sht3x_drv_t *drv, uint8_t *data)
{
    int32_t ret;
    uint16_t cmd;

    // 参数检查
    SHT3X_CHECK_NULL_PTR_RET(drv, HDF_ERR_INVALID_OBJECT);
    SHT3X_CHECK_NULL_PTR_RET(data, HDF_ERR_INVALID_OBJECT);

    cmd = _sht3xDrvGetReadDataCmd(drv);

    // 发送 cmd 然后读取6个字节
    // send cmd and read 6 byte
    ret = _sht3xDrvReadDataByCmd(drv, cmd, data, 6);
    return ret;
}

/*
轮询测量模式下读取测量到的温湿度数据
read data at poll measure mode
*/
static int32_t _sht3xDrvReadDataPoll(sht3x_drv_t *drv, uint8_t *data)
{
    int32_t ret;
    uint16_t cmd;
    int times = 20;// 默认超时时间 20ms

    SHT3X_CHECK_NULL_PTR_RET(drv, HDF_ERR_INVALID_OBJECT);
    SHT3X_CHECK_NULL_PTR_RET(data, HDF_ERR_INVALID_OBJECT);

    // 获取要发送的指令
    cmd = _sht3xDrvGetReadDataCmd(drv);

    // 先发送指令触发一次测量
    // send cmd to trigger once measure
    ret = _sht3xDrvSendCmd(drv, cmd);
    if (ret) {
        HDF_LOGE("_sht3xDrvSendCmd fail, cmd : %#x, ret : %#x.", cmd, ret);
        return HDF_FAILURE;
    }

    // 轮询读取数据
    // read data 
    while(times >= 0) {

        // 不能太频繁 
        // 试过 1ms 2ms 都会导致测量出问题
        // 5ms时 高重复度也会出问题

        OsalMSleep(5);
        times -= 5;

        // 尝试进行数据读取
        // try to read data
        ret = _sht3xDrvReadData(drv, data, 6);
        if (ret == HDF_SUCCESS) break;
    }

    return ret;
}

/*
时钟拉伸测量模式下读取测量到的温湿度数据
read data at clk stretch measure mode
*/
static int32_t _sht3xDrvReadDataClkStretch(sht3x_drv_t *drv, uint8_t *data)
{
    int32_t ret;
    uint16_t cmd;

    SHT3X_CHECK_NULL_PTR_RET(drv, HDF_ERR_INVALID_OBJECT);
    SHT3X_CHECK_NULL_PTR_RET(data, HDF_ERR_INVALID_OBJECT);

    // 获取要发送的指令
    cmd = _sht3xDrvGetReadDataCmd(drv);

    // 先发送指令触发一次测量
    // send cmd to trigger once measure
    ret = _sht3xDrvSendCmd(drv, cmd);
    if (ret) {
        HDF_LOGE("_sht3xDrvSendCmd fail, cmd : %#x, ret : %#x.", cmd, ret);
        return HDF_FAILURE;
    }

    // if i2c bus unsupport "clk_stretch", wait for a while
    // OsalMSleep(20);
    
    // 读取数据
    // read 6 bytes
    // 该设备支持 clk_stretch, 所以可以不用延时,直接读取
    // this i2c bus support clk_stretch
    ret = _sht3xDrvReadData(drv, data, 6);
    if (ret) {
        HDF_LOGE("_sht3xDrvReadData fail, ret : %#x.", ret);
        return HDF_FAILURE;
    }

    return ret;
}

//////////////////////////////////////////////////
// 发送指令
//////////////////////////////////////////////////

/*
发送停止命令
send cmd to stop period measure
*/
static int32_t _sht3xDrvStopPeriod(sht3x_drv_t *drv)
{
    return _sht3xDrvSendCmd(drv, CMD_MEAS_PERI_STOP);// 发送停止指令
}

/*
发送软复位指令
send cmd to soft reset
*/
static int32_t _sht3xDrvSoftReset(sht3x_drv_t *drv)
{
    return _sht3xDrvSendCmd(drv, CMD_SOFT_RESET);// 发送复位命令
}

// 采样线程
static int sht3xDrvSamplingThreadEntry(void *arg)
{
    sht3x_drv_t *drv = NULL;
    int64_t interval;// 采样周期
    uint8_t status;

    SHT3X_CHECK_NULL_PTR_RET(arg, HDF_FAILURE);

    // 获取设备节点
    drv = (sht3x_drv_t *)arg;

    // 设置线程状态为 START
    _sht3xDrvSetThreadStatus(drv, SENSOR_THREAD_START);

    while(1)
    {
        // 获取线程运行状态
        status = _sht3xDrvGetThreadStatus(drv);

        // 判断当前线程执行状态
        if (status == SENSOR_THREAD_RUNNING) { // 线程运行中

            sht3xDrvReadData((DevHandle)drv);// 进行一次测量

        } else if (status == SENSOR_THREAD_STOPPING) { // 线程准备退出

            _sht3xDrvSetThreadStatus(drv, SENSOR_THREAD_STOPPED);
            HDF_LOGE("[%s] Exit.", __FUNCTION__);
            return HDF_SUCCESS;
        }

        // 获取延时时间
        interval = sht3xDrvGetSamplingInterval((DevHandle)drv);
        if (interval <= 0) {
            interval = 1000;// 默认1000ms延时
        }

        OsalMSleep(interval);
    }

    return HDF_SUCCESS;
}

//////////////////////////////////////////////////
// 对外接口
// public interface
//////////////////////////////////////////////////

/*
初始化设备
*/
DevHandle sht3xDrvOpen(sht3xDrvCfg *cfg)
{
    int32_t ret = HDF_SUCCESS;
    sht3x_drv_t *drv = NULL;
    DevHandle host = NULL;

    SHT3X_CHECK_NULL_PTR_RET(cfg, NULL);

    // 创建节点,分配内存
    drv = (sht3x_drv_t *)OsalMemCalloc(sizeof(sht3x_drv_t));
    if (drv == NULL) {
        // 创建节点失败,返回
        HDF_LOGE("OsalMemCalloc fail.");
        goto sht3xDrvInitExit1;
    }

    // 初始化锁
    ret = OsalMutexInit(&(drv->mutex));
    if (ret != HDF_SUCCESS) {
        // 初始化锁失败,返回
        HDF_LOGE("OsalMutexInit fail, ret : %#x.", ret);
        goto sht3xDrvInitExit2;
    }

    ret = _sht3xDrvMutexLock(drv);
    if (ret != HDF_SUCCESS) {
        // 获取锁失败,返回
        HDF_LOGE("_sht3xDrvMutexLock fail, ret : %#x.", ret);
        goto sht3xDrvInitExit2;
    }

    // 打开I2C总线
    host = I2cOpen(cfg->i2cPortNum);
    if (host == NULL) {
        // 打开I2C总线失败,返回
        HDF_LOGE("I2cOpen fail.");
        goto sht3xDrvInitExit3;
    }

    // 设置私有属性
    _sht3xDrvSetHost(drv, host);

    // 设置从器件地址
    if (cfg->adVal) {
        _sht3xDrvSetSlaveAddr(drv, 0x45);
    } else {
        _sht3xDrvSetSlaveAddr(drv, 0x44);
    }

    // 创建数据采集线程
    sprintf(drv->samplingThreadName, SHT3X_THREAD_NAME_FMT, _sht3xDrvGetSlaveAddr(drv), cfg->i2cPortNum);
    ret = CreateSensorThread(&(drv->samplingThread), sht3xDrvSamplingThreadEntry, drv->samplingThreadName, (void *)drv);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("CreateSensorThread fail.");
        goto sht3xDrvInitExit3;
    }

    _sht3xDrvMutexUnLock(drv);

    return (DevHandle)drv;

sht3xDrvInitExit3:
    _sht3xDrvMutexUnLock(drv);// 解锁
sht3xDrvInitExit2:
    OsalMemFree(drv);// 释放内存
sht3xDrvInitExit1:
    return NULL;
}

/*
关闭sht3x
*/
void sht3xDrvClose(DevHandle dev)
{
    int32_t ret = HDF_SUCCESS;
    DevHandle host = NULL;
    sht3x_drv_t *drv = (sht3x_drv_t *)dev;

    SHT3X_CHECK_NULL_PTR(drv);

    // 线程退出
    DestroySensorThread(&(drv->samplingThread), &(drv->samplingThreadStatus));

    // 上锁
    ret = _sht3xDrvMutexLock(drv);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("_sht3xDrvMutexLock fail, ret : %#x.", ret);
        return;
    }

    _sht3xDrvSoftReset(drv);// 软复位
    _sht3xDrvDisable(drv);// 去使能

    // 关闭总线
    host = _sht3xDrvGetHost(drv);
    if (host != NULL) {
        I2cClose(host);
    }

    _sht3xDrvMutexUnLock(drv);// 解锁

    OsalMutexDestroy(&(drv->mutex));// 销毁锁
    OsalMemFree(drv);// 释放内存
}

/*
配置设备测量模式
set device work mode
see @WorkMode in sht3x.h
*/
int32_t sht3xDrvSetMode(DevHandle dev, uint8_t mode)
{
    int32_t ret = HDF_SUCCESS;
    int64_t interval;
    sht3x_drv_t *drv = (sht3x_drv_t *)dev;

    SHT3X_CHECK_NULL_PTR_RET(drv, HDF_ERR_INVALID_OBJECT);

    ret = _sht3xDrvMutexLock(drv);
    if (ret != HDF_SUCCESS) {
        return HDF_FAILURE;
    }

    // 如果设备已经使能了,直接返回
    // if device is enabled, return
    if (_sht3xDrvIsEnabled(drv)) {
        HDF_LOGE("device is enabled.");
        ret = HDF_FAILURE;
        goto sht3xDrvSetModeExit;
    }

    // 设置模式
    // set work mode
    ret = _sht3xDrvSetMode(drv, mode);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("_sht3xDrvSetMode fail, ret : %#x.", ret);
        ret = HDF_FAILURE;
        goto sht3xDrvSetModeExit;
    }

    // 获取模式
    // get current work mode
    mode = _sht3xDrvGetMode(drv);

    // 设置测量模式
    // set measure mode
    ret = _sht3xDrvSetMeasureMode(drv, mode);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("_sht3xDrvSetMode fail, ret : %#x.", ret);
        ret = HDF_FAILURE;
        goto sht3xDrvSetModeExit;
    }

    // 如果是周期测量模式,设置采样频率
    // if is period measure mode, set sampling interval
    if (SHT3X_PERIOD == _sht3xDrvGetMeasureMode(drv)) {
        interval = _sht3xDrvGetIntervalByFreq(_sht3xDrvGetFreqByMode(mode));// 获取采样频率 get sampling interval
        if (interval == -1) {
            HDF_LOGE("_sht3xDrvGetIntervalByFreq fail, freq : %#x.", _sht3xDrvGetFreqByMode(mode));
            ret = HDF_FAILURE;
            goto sht3xDrvSetModeExit;
        }
    } else {
        interval = 1000;// 非周期模式默认周期 1000ms
    }

    // 设置采样频率
    // set sampling interval
    _sht3xDrvSetSamplingInterval(drv, interval);

sht3xDrvSetModeExit:

    _sht3xDrvMutexUnLock(drv);

    return ret;
}

/*
使能设备
enable device
*/
int32_t sht3xDrvEnable(DevHandle dev)
{
    int32_t ret = HDF_FAILURE;
    uint16_t cmd;
    sht3x_drv_t *drv = (sht3x_drv_t *)dev;

    SHT3X_CHECK_NULL_PTR_RET(drv, HDF_ERR_INVALID_OBJECT);

    ret = _sht3xDrvMutexLock(drv);
    if (ret != HDF_SUCCESS) {
        return HDF_FAILURE;
    }

    // 如果已经被使能过
    // if device is enabled, return
    if (_sht3xDrvIsEnabled(drv)) {
        HDF_LOGE("device is enabled.");
        ret = HDF_FAILURE;
        goto sht3xDrvEnableExit;
    }

    // 获取指令
    // get cmd by work mode
    ret = _sht3xDrvGetCmdByMode(drv, &cmd);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("_sht3xDrvGetCmdByMode fail, ret : %#x.", ret);
        ret = HDF_FAILURE;
        goto sht3xDrvEnableExit;
    }

    switch (_sht3xDrvGetMeasureMode(drv))
    {
        case SHT3X_PERIOD: // if is period measure mode, send cmd to start period measure
            // 发送指令
            ret = _sht3xDrvSendCmd(drv, cmd);
            cmd = CMD_FETCH_DATA;// read data cmd is $CMD_FETCH_DATA
        break;
        case SHT3X_POLL:
        case SHT3X_CLK_STRETCH:// if is poll or clk stretch mode, stop device period measure
            // 发送停止周期测量模式指令
            ret = _sht3xDrvStopPeriod(drv);
        break;
        default:
            ret = HDF_FAILURE;
            HDF_LOGE("mode not set or mode err.");
        break;
    }

    if (ret == HDF_SUCCESS) {
        // 配置当前模式下,数据读取的指令
        // set read data cmd at current mode
        _sht3xDrvSetReadDataCmd(drv, cmd);
        _sht3xDrvSetTimeStamp(drv, OsalGetSysTimeMs());// 设置时间戳
        _sht3xDrvSetThreadStatus(drv, SENSOR_THREAD_RUNNING);// 设置线程状态为 RUNNING
        _sht3xDrvEnable(drv);// 使能成功
    }

sht3xDrvEnableExit:

    _sht3xDrvMutexUnLock(drv);

    return ret;
}

/* 
失能设备
disable device
*/
int32_t sht3xDrvDisable(DevHandle dev)
{
    int32_t ret = HDF_SUCCESS;
    sht3x_drv_t *drv = (sht3x_drv_t *)dev;

    SHT3X_CHECK_NULL_PTR_RET(drv, HDF_ERR_INVALID_OBJECT);

    ret = _sht3xDrvMutexLock(drv);
    if (ret != HDF_SUCCESS) {
        return HDF_FAILURE;
    }

    // 发送停止命令
    // stop period measure
    // poll or clk stretch mode do nothing
    ret = _sht3xDrvStopPeriod(drv);
    if (ret == HDF_SUCCESS) {
        _sht3xDrvSetThreadStatus(drv, SENSOR_THREAD_START);// 设置线程状态为 START
        _sht3xDrvDisable(drv);// 设备进入失能模式
    }

    _sht3xDrvMutexUnLock(drv);

    return ret;
}

/* 
设备软复位
device soft reset
*/
int32_t sht3xDrvSoftReset(DevHandle dev)
{
    int32_t ret;
    sht3x_drv_t *drv = (sht3x_drv_t *)dev;

    SHT3X_CHECK_NULL_PTR_RET(drv, HDF_ERR_INVALID_OBJECT);

    ret = _sht3xDrvMutexLock(drv);
    if (ret != HDF_SUCCESS) {
        return HDF_FAILURE;
    }

    // 发送复位命令
    // send cmd
    ret = _sht3xDrvSoftReset(drv);
    if (ret == HDF_SUCCESS) {
        _sht3xDrvSetThreadStatus(drv, SENSOR_THREAD_START);// 设置线程状态为 START
        _sht3xDrvDisable(drv);// 复位之后设备进入失能模式
        OsalMSleep(50);
    }

    _sht3xDrvMutexUnLock(drv);

    return ret;
}

/* 
读取当前温湿度数据
read data from device
*/
int32_t sht3xDrvReadData(DevHandle dev)
{
    int32_t ret;
    uint8_t recv_data[6] = {0}; // 原始数据缓冲区
    sht3x_drv_t *drv = (sht3x_drv_t *)dev;

    SHT3X_CHECK_NULL_PTR_RET(drv, HDF_ERR_INVALID_OBJECT);

    ret = _sht3xDrvMutexLock(drv);
    if (ret != HDF_SUCCESS) {
        return HDF_FAILURE;
    }

    // 设备未使能
    if (!_sht3xDrvIsEnabled(drv)) {
        HDF_LOGE("device is not enable.");
        ret = HDF_FAILURE;
        goto sht3xDrvReadDataExit;
    }

    // 周期限制
    if (_sht3xDrvGetTimeStamp(drv) + _sht3xDrvGetSamplingInterval(drv) > OsalGetSysTimeMs()) {
        ret = HDF_SUCCESS;
        goto sht3xDrvReadDataExit;
    }

    // 判断设备测量模式
    switch (_sht3xDrvGetMeasureMode(drv))
    {
        case SHT3X_POLL:// 轮询
            ret = _sht3xDrvReadDataPoll(drv, recv_data);
            break;
        case SHT3X_CLK_STRETCH:// 时钟拉伸
            ret = _sht3xDrvReadDataClkStretch(drv, recv_data);
            break;
        case SHT3X_PERIOD:// 周期
            ret = _sht3xDrvReadDataPeriod(drv, recv_data);
            break;
        default:
            ret = HDF_FAILURE;
            break;
    }

    // 读取原始数据成功,进行数据处理
    if (ret == HDF_SUCCESS) {
        ret = sht3xUtilsVerifyCrc(recv_data + 0, 2, recv_data[2]);
        ret |= sht3xUtilsVerifyCrc(recv_data + 3, 2, recv_data[5]);
    }

    // 校验成功,转换温湿度
    // if crc check is OK, calc raw data to sensor data
    if (ret == 0) {
        _sht3xDrvSetTimeStamp(drv, OsalGetSysTimeMs());// 设置时间戳

        drv->data.temperature = sht3xUtilsCalcTemperature(recv_data[0] << 8 | recv_data[1]);
        drv->data.humidity = sht3xUtilsCalcHumidity(recv_data[3] << 8 | recv_data[4]);

        ret = HDF_SUCCESS;
    }

sht3xDrvReadDataExit:

    _sht3xDrvMutexUnLock(drv);

    return ret;
}

/* 
获取温度数据
get temperature data from buffer
*/
int32_t sht3xDrvGetTemperature(DevHandle dev, float *temperature)
{
    int32_t ret = HDF_SUCCESS;
    sht3x_drv_t *drv = (sht3x_drv_t *)dev;

    SHT3X_CHECK_NULL_PTR_RET(drv, HDF_ERR_INVALID_OBJECT);
    SHT3X_CHECK_NULL_PTR_RET(temperature, HDF_ERR_INVALID_OBJECT);

    ret = _sht3xDrvMutexLock(drv);
    if (ret != HDF_SUCCESS) {
        return HDF_FAILURE;
    }

    // 是否已经使能
    if (!_sht3xDrvIsEnabled(drv)) {
        HDF_LOGE("device is not enable.");
        return HDF_FAILURE;
    }

    // 获取温度数据
    *temperature = drv->data.temperature;

    _sht3xDrvMutexUnLock(drv);

    return ret;
}

/* 
获取湿度数据
get humidity data from buffer
*/
int32_t sht3xDrvGetHumidity(DevHandle dev, float *humidity)
{
    int32_t ret = HDF_SUCCESS;
    sht3x_drv_t *drv = (sht3x_drv_t *)dev;

    SHT3X_CHECK_NULL_PTR_RET(drv, HDF_ERR_INVALID_OBJECT);
    SHT3X_CHECK_NULL_PTR_RET(humidity, HDF_ERR_INVALID_OBJECT);

    ret = _sht3xDrvMutexLock(drv);
    if (ret != HDF_SUCCESS) {
        return HDF_FAILURE;
    }

    // 是否已经使能
    if (!_sht3xDrvIsEnabled(drv)) {
        HDF_LOGE("device is not enable.");
        return HDF_FAILURE;
    }

    // 获取湿度数据
    *humidity = drv->data.humidity;

    _sht3xDrvMutexUnLock(drv);

    return ret;
}

/* 
设置采样周期
set sampling interval
*/
int32_t sht3xDrvSetSamplingInterval(DevHandle dev, int64_t interval)
{
    int32_t ret = HDF_SUCCESS;
    sht3x_drv_t *drv = (sht3x_drv_t *)dev;

    SHT3X_CHECK_NULL_PTR_RET(drv, HDF_ERR_INVALID_OBJECT);

    ret = _sht3xDrvMutexLock(drv);
    if (ret != HDF_SUCCESS) {
        return HDF_FAILURE;
    }

    // 周期测量模式不支持设置采样周期
    // if current is period measure mode,can not set sampling interval(sampling interval set by work mode)
    if (_sht3xDrvGetMeasureMode(drv) == SHT3X_PERIOD) {
        goto sht3xDrvSetSamplingIntervalExit;
    }

    // 设置采样周期
    ret = _sht3xDrvSetSamplingInterval(drv, interval);

sht3xDrvSetSamplingIntervalExit:

    _sht3xDrvMutexUnLock(drv);

    return ret;
}

/* 
获取当前设备的采样周期
get current device sampling interval
*/
int64_t sht3xDrvGetSamplingInterval(DevHandle dev)
{
    int32_t ret;
    int64_t interval = 0;
    sht3x_drv_t *drv = (sht3x_drv_t *)dev;

    SHT3X_CHECK_NULL_PTR_RET(drv, HDF_ERR_INVALID_OBJECT);

    ret = _sht3xDrvMutexLock(drv);
    if (ret != HDF_SUCCESS) {
        return HDF_FAILURE;
    }

    // 获取设备的采样频率
    interval = _sht3xDrvGetSamplingInterval(drv);

    _sht3xDrvMutexUnLock(drv);

    return interval;
}
